package parser;

import java.util.ArrayList;
import java.util.HashMap;

import componentes.Memoria;

import excecao.ExcecaoMemoria;
import excecao.ExcecaoParser;

import microprocessador.ULA;


public class Parser{
	
	// Mantém a posição atualizada para inserir labels	
	private int pos;	
	// Mantém a label e a posição de memória onde será inserida
	private HashMap<String, Integer> labels;
	// Vetor que guarda temporariamente as instruções lidas na entrada 
	private ArrayList<Instrucao> vetor;
	private static Parser instancia;

	public static void criaInstancia(){
		if (instancia == null){
			instancia = new Parser();
		}
	}
	
	public static Parser getInstancia(){
		return instancia;
	}
	
	private Parser(){
		DicionarioInstrucao.criaInstancia();
	}
	
	public void parserTexto(String texto) throws ExcecaoParser{
		texto = DicionarioInstrucao.filtro(texto);
		
		pos = 0;
		labels = new HashMap<String, Integer>();
		vetor = new ArrayList<Instrucao>();
		
		Instrucao i = null;
		String[] instrucoes = texto.split(";");
		
		for (String instrucao : instrucoes){
			if (instrucao.equals("")){
				continue;
			}
			
			String[] s = instrucao.split(":");
			if (s.length == 2){
				labels.put(DicionarioInstrucao.filtro(s[0]), pos);
				i = DicionarioInstrucao.getInstrucao(s[1] + ";");
			}
			else{				
				i = DicionarioInstrucao.getInstrucao(s[0] + ";");
			}
			insereVetor(i);
		}
	}
	
	private void insereVetor(Instrucao instrucao){
		if (instrucao == null){
			return;
		}
		
		if (instrucao.getImediato() == null && instrucao.getLabel() == null){
			pos += 1;
			vetor.add(instrucao);
			return;
		}
		if (instrucao.getImediato() != null){
			pos += 2;
			vetor.add(instrucao);
		}
		if (instrucao.getLabel() != null){
			pos += 2;
			vetor.add(instrucao);
		}		
	}	
	
	public void insereMemoria(int pos_inicial, Memoria memoria) throws ExcecaoMemoria, ExcecaoParser{
		String posicao, imediato, label;
		
		pos = pos_inicial;
		for (Instrucao inst : vetor){
			posicao = converteBin(pos++);
			memoria.setDado(posicao, inst.getCodigo());
			if (inst.getImediato() != null){
				posicao = converteBin(pos++);
				imediato = converteBin(inst.getImediato());
				memoria.setDado(posicao, imediato);
			}
			if (inst.getLabel() != null){
				posicao = converteBin(pos++);
				if (labels.containsKey(inst.getLabel())){
					label = converteBin(labels.get(inst.getLabel()) + pos_inicial);
				}
				else{
					throw new ExcecaoParser("Label inexistente - " + inst.getLabel());
				}
				memoria.setDado(posicao, label);
			}					
		}
	}
	
	private String converteBin(int numero){
		if (numero < 0){
			return ULA.complementoA2(Integer.toBinaryString((-1)*numero));
		}
		else{
			String i = Integer.toBinaryString(numero);
			return ULA.geraComplemento(i.length()) + i;
		}
	}	
}